package com.ccrfid.rmc6.appconfig.websocket;

import com.ccrfid.rmc6.entity.mattress.BedAlarmView;
import com.ccrfid.rmc6.entity.mattress.MattressStateEntity;
import com.ccrfid.rmc6.util.JsonUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.*;

@Component
public class MattressWebSocketHandler extends TextWebSocketHandler {
    private static final Logger logger = LoggerFactory.getLogger(MattressWebSocketHandler.class);

    private Set<WebSocketSession> webSocketSessionSet;
    private BlockingQueue<MattressStateEntity> mattressStateQueue;
    private BlockingQueue<BedAlarmView> bedAlarmQueue;
    private ExecutorService executorService;

    public MattressWebSocketHandler() {
        this.webSocketSessionSet = ConcurrentHashMap.newKeySet();
        this.mattressStateQueue = new LinkedBlockingDeque<>(1024 * 8);
        this.bedAlarmQueue = new LinkedBlockingDeque<>(1024 * 2);
        this.executorService = Executors.newFixedThreadPool(2);
    }

    @PostConstruct
    private void init() {
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        List<MattressStateEntity> list = new ArrayList<>();
                        int count = mattressStateQueue.drainTo(list);
                        if (count > 0) {
                            broadcastMattressStateMsg(list);
                        }
                        TimeUnit.SECONDS.sleep(3);
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }

                }
            }
        });
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        List<BedAlarmView> list = new ArrayList<>();
                        int count = bedAlarmQueue.drainTo(list);
                        if (count > 0) {
                            broadcastBedAlarmMsg(list);
                        }

                        TimeUnit.SECONDS.sleep(3);
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
            }
        });
    }

    private void broadcastMattressStateMsg(List<MattressStateEntity> list) {
        for (WebSocketSession session : webSocketSessionSet) {
            if (session.isOpen()) {
                String txt = JsonUtil.INSTANCE.writeValueAsString(new MsgEntity<>("mattress-states", list));
                synchronized (session) {
                    try {
                        session.sendMessage(new TextMessage(txt));
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                }
            }
        }
    }

    private void broadcastBedAlarmMsg(List<BedAlarmView> list) {
        for (WebSocketSession session : webSocketSessionSet) {
            if (session.isOpen()) {
                String txt = JsonUtil.INSTANCE.writeValueAsString(new MsgEntity<>("bed-alarms", list));
                synchronized (session) {
                    try {
                        session.sendMessage(new TextMessage(txt));
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                }
            }
        }
    }

    public boolean inputMattressState(MattressStateEntity mattressState) {
        return mattressStateQueue.offer(mattressState);
    }

    public boolean inputBedAlarm(BedAlarmView bedAlarm) {
        return bedAlarmQueue.offer(bedAlarm);
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        logger.debug("mattress WebSocketSession: {}, handleTransportError: {}", session.getId(), exception.getMessage());
        if (session.isOpen()) {
            session.close();
        }
        webSocketSessionSet.remove(session);
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        logger.debug("mattress webSocketSession Connection Established {}, {}", session.getUri(), session.getId());
        webSocketSessionSet.add(session);
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        logger.debug("mattress webSocketSession: {}, handleTextMessage: {}", session.getId(), message);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        logger.debug("mattress webSocketSession Connection Closed. {}, {}", session.getUri(), session.getId());
        webSocketSessionSet.remove(session);
    }
}
